// Copyright (c) 2016, Open DICOMweb Project. All rights reserved.
// Use of this source code is governed by the open source license
// that can be found in the LICENSE file.
// Author: Jim Philbin <jfphilbin@gmail.edu>
// See the AUTHORS file for other contributors.

import 'package:dicom_core/src/element/base/element.dart';
import 'package:dicom_core/src/tag/tag_lib.dart';

class Entry {
  final Element? element;
  final String? msg;

  Entry(this.element, [this.msg]);

  Tag? get tag => (element != null) ? element!.tag : null;

  String? get keyword => (element != null) ? element!.tag.keyword : null;

  String get json => '''
  { "@type": "Message",b
    "Element": '$element',
    "Message": "$msg" }
  ''';

  @override
  String toString() => (msg == null) ? ' $element' : ' $element - $msg';

  static Entry invalidNumberOfValues(Element e) =>
      Entry(e, 'Element with an invalid Number of values');
}

/// A warning about a Dataset or an Element in a Dataset.
class StatusReport {
  final String name;
  final List<Entry> entries = <Entry>[];
  bool doPrint;

  StatusReport(this.name, {this.doPrint: true});

  /// Turn console printing on.
  bool get printOn => doPrint = true;

  /// Turn console printing off.
  bool get printOff => doPrint = false;

  // Log(this.ieSeverity);
  Entry log(Element e, String? message) {
    final r = Entry(e, message);
    entries.add(r);
    if (doPrint) print(r);
    return r;
  }

  Entry call(Element e, String msg) => log(e, msg);

  /// Log message at Level [Level.debug].
  Entry debug(Element e, [String? msg]) => log(e, msg);

  /// Log message at Level [Level.config].
  Entry config(Element e, [String? msg]) => log(e, msg);

  /// Log message at Level [Level.info].
  Entry info(Element e, [String? msg]) => log(e, msg);

  /// Log message at Level [Level.warn].
  Entry warning(Element e, [String? msg]) => log(e, msg);

  /// Log message at Level [Level.error].
  Entry error(Element e, [String? msg]) => log(e, msg);

  /// Log message at Level [Level.quarantine].
  Entry quarantine(Element e, [String? msg]) => log(e, msg);

  /// Log message at Level [Level.abort].
  Entry abort(Element e, [String? msg]) => log(e, msg);

  /// Log message at Level [Level.fatal].
  Entry fatal(Element e, [String? msg]) {
    final entry = log( e, msg);
    throw FatalError(entry);
  }

  void add(Entry m) => entries.add(m);

  String get json => '''
  {"@type": "StatusLog",
   "@date": ${DateTime.now()},
   "Messages": [ ${entries.join(",")} ] }
   ''';

  @override
  String toString() => 'Status Log:\n  ${entries.join("\n  ")}';

  Entry invalidNumberOfValues(Element e) =>
      error(e, 'Element with an invalid Number of values');
}

class FatalError extends Error {
  Entry entry;

  FatalError(this.entry);

  @override
  String toString() => '$entry';
}
